package cn.wolfcode.service.impl;

import cn.wolfcode.common.exception.BusinessException;
import cn.wolfcode.common.web.CodeMsg;
import cn.wolfcode.common.web.Result;
import cn.wolfcode.domain.*;
import cn.wolfcode.feign.AliPayFeignApi;
import cn.wolfcode.feign.IntergralFeignApi;
import cn.wolfcode.mapper.OrderInfoMapper;
import cn.wolfcode.mapper.PayLogMapper;
import cn.wolfcode.mapper.RefundLogMapper;
import cn.wolfcode.mapper.SeckillProductMapper;
import cn.wolfcode.mq.MQConstant;
import cn.wolfcode.mq.OrderMQResult;
import cn.wolfcode.redis.SeckillRedisKey;
import cn.wolfcode.service.IOrderInfoService;
import cn.wolfcode.service.ISeckillProductService;
import cn.wolfcode.util.IdGenerateUtil;
import cn.wolfcode.web.msg.SeckillCodeMsg;
import com.alibaba.fastjson.JSON;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.sound.sampled.Line;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Created by wolfcode-lanxw
 */
@Service
@Slf4j
public class OrderInfoSeviceImpl implements IOrderInfoService {
    @Autowired
    private ISeckillProductService seckillProductService;
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private PayLogMapper payLogMapper;
    @Autowired
    private RefundLogMapper refundLogMapper;
    @Autowired
    private SeckillProductMapper seckillProductMapper;
    @Autowired
    private RocketMQTemplate rocketMQTemplate;
    @Autowired
    private AliPayFeignApi aliPayFeignApi;
    @Autowired
    private IntergralFeignApi intergralFeignApi;
    @Value("${pay.returnUrl}")
    private String returnUrl;
    @Value("${pay.notifyUrl}")
    private String notifyUrl;

    /**
     * 积分退款
     * @param orderInfo
     */
    @Override
    @GlobalTransactional
    public void refundIntergral(OrderInfo orderInfo) {
        //插入退款日志记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());
        refundLog.setRefundTime(new Date());
        refundLog.setRefundAmount(orderInfo.getSeckillPrice() + "");
        refundLog.setRefundReason("hkj不喜欢");
        refundLog.setRefundType(OrderInfo.PAYTYPE_INTERGRAL);
        refundLogMapper.insert(refundLog);
        //远程调用积分服务进行退款（加积分）
        OperateIntergralVo vo = new OperateIntergralVo();
        vo.setPk(orderInfo.getOrderNo());
        vo.setValue(orderInfo.getIntergral());
        vo.setInfo(orderInfo.getProductName());
        vo.setUserId(orderInfo.getUserId());
        Result<String> result = intergralFeignApi.incrIntergral(vo);
        if(result == null || result.hasError()){
            throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
        }

        int i = 1 / 0;

        //修改状态为退款
        orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(),OrderInfo.STATUS_REFUND);
        //回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        //修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }

    /**
     * 积分支付
     * @param orderNo
     * @param type
     */
    @Override
    @GlobalTransactional
    public void payIntegral(String orderNo, int type) {
        //插入流水记录
        OrderInfo orderInfo = this.find(orderNo);
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderInfo.getOrderNo());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payLog.setNotifyTime(sdf.format(new Date()));
        payLog.setTotalAmount(orderInfo.getSeckillPrice() +"");
        payLog.setPayType(type);
        payLogMapper.insert(payLog);
        //远程调用积分服务进行支付
        OperateIntergralVo vo = new OperateIntergralVo();
        vo.setPk(orderNo);
        vo.setValue(orderInfo.getIntergral());
        vo.setInfo(orderInfo.getProductName());
        vo.setUserId(orderInfo.getUserId());
        Result<String> result = intergralFeignApi.descIntergral(vo);
        if(result == null || result.hasError()){
            if (result.getCode()==500207){
                throw new BusinessException(SeckillCodeMsg.INTERGRAL_SERVER_ERROR);
            }else {
                CodeMsg codeMsg = new CodeMsg();
                codeMsg.setCode(result.getCode());
                codeMsg.setMsg(result.getMsg());
                throw new BusinessException(codeMsg);
            }
        }
        //修改订单状态为已支付
        orderInfoMapper.changePayStatus(orderNo, OrderInfo.STATUS_ACCOUNT_PAID, OrderInfo.PAYTYPE_INTERGRAL);
    }

    /**
     * 在线退款
     * @param orderInfo
     */
    @Override
    public void refundOnline(OrderInfo orderInfo) {
        //插入一条流水记录
        RefundLog refundLog = new RefundLog();
        refundLog.setOutTradeNo(orderInfo.getOrderNo());
        refundLog.setRefundTime(new Date());
        refundLog.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundLog.setRefundReason("yoona不喜欢");
        refundLog.setRefundType(OrderInfo.PAYTYPE_ONLINE);
        refundLogMapper.insert(refundLog);
        //远程调用支付服务进行退款操作
        RefundVo refundVo = new RefundVo();
        refundVo.setOutTradeNo(orderInfo.getOrderNo());
        refundVo.setRefundAmount(orderInfo.getSeckillPrice()+"");
        refundVo.setRefundReason("yoona不喜欢");
        //true代表付款成功，false代表付款失败
        Result<Boolean> result = aliPayFeignApi.refundOnline(refundVo);
        if(result == null || result.hasError() || !result.getData()){
            throw new BusinessException(SeckillCodeMsg.OPT_SECKILL_ERROR);
        }
        //修改订单状态为退款
        orderInfoMapper.changeRefundStatus(orderInfo.getOrderNo(),OrderInfo.STATUS_REFUND);
        //回补真实库存
        seckillProductMapper.incrStock(orderInfo.getSeckillId());
        //回补预库存
        seckillProductService.syncRedisStockCount(orderInfo.getSeckillTime(),orderInfo.getSeckillId());
        //修改本地标识
        rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderInfo.getSeckillId());
    }

    /**
     * 支付成功
     * @param orderNo
     */
    @Override
    public void paySuccess(String orderNo) {
        //插入一条流水信息
        OrderInfo orderInfo = this.find(orderNo);
        PayLog payLog = new PayLog();
        payLog.setTradeNo(orderInfo.getOrderNo());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        payLog.setNotifyTime(sdf.format(new Date()));
        payLog.setTotalAmount(orderInfo.getSeckillPrice() + "");
        payLog.setPayType(OrderInfo.PAYTYPE_ONLINE);
        payLogMapper.insert(payLog);
        //修改订单状态,通过订单和支付方式将状态改为已付款
        orderInfoMapper.changePayStatus(orderNo,OrderInfo.STATUS_ACCOUNT_PAID,OrderInfo.PAYTYPE_ONLINE);
    }
    /**
     * 在线支付
     * @param orderNo
     */
    @Override
    public String payOnline(String orderNo, int type) {
        //在调用支付宝支付接口进行支付操作，需要给支付宝返回一个字符串
        OrderInfo orderInfo = this.find(orderNo);
        //远程服务方法参数需要传递一个PayVo
        //封装PayVo，需要根据orderNo去redis中查询OrderInfo对象，才能对PayVo进行封装
        PayVo payVo = new PayVo();
        payVo.setOutTradeNo(orderInfo.getOrderNo());
        payVo.setTotalAmount(orderInfo.getSeckillPrice() + "");
        payVo.setSubject(orderInfo.getProductName());
        payVo.setBody(orderInfo.getProductName());
        payVo.setReturnUrl(returnUrl);
        payVo.setNotifyUrl(notifyUrl);
        //远程调用支付服务，完成支付操作，并放回一个登录的表单页面字符串
        Result<String> result = aliPayFeignApi.payOnline(payVo);
        if(result != null && !result.hasError()){
            return result.getData();
        }
        return "";
    }

    @Override
    public OrderInfo find(String orderNo) {
        //不再从数据库中查询
        //return orderInfoMapper.find(orderNo);
        //从redis中查询
        Object obj_json = redisTemplate.opsForHash().get(SeckillRedisKey.SECKILL_ORDER_HASH.getRealKey(""), orderNo);
        if(StringUtils.isEmpty(obj_json  + "")){
            return null;
        }
        return JSON.parseObject(obj_json+"",OrderInfo.class);
    }

    @Override
    @Transactional
    public String doSeckill(int time, Long seckillId, Long phone) {
        //减少库存
        int count = seckillProductMapper.decrStock(seckillId);//数据库受影响的行数
        if(count == 0){
            throw new BusinessException(SeckillCodeMsg.SECKILL_STOCK_OVER);
        }
        //创建订单并保存
        String orderNum = createOrderInfo(time,seckillId,phone);
        //向redis中存入一个key（防止用户进行重复下单）
        redisTemplate.opsForSet().add(SeckillRedisKey.SECKILL_ORDER_SET.getRealKey(time + ""), phone + ":" + seckillId);
        return orderNum;
    }

    private String createOrderInfo(int time, Long seckillId, Long phone) {
        SeckillProductVo vo = seckillProductService.find(time, seckillId);
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setOrderNo(IdGenerateUtil.get().nextId() + "");
        orderInfo.setUserId(phone);
        orderInfo.setProductId(vo.getProductId());
        orderInfo.setProductImg(vo.getProductImg());
        orderInfo.setDeliveryAddrId(1L);
        orderInfo.setProductName(vo.getProductName());
        orderInfo.setProductCount(vo.getStockCount());
        orderInfo.setProductPrice(vo.getProductPrice());
        orderInfo.setSeckillPrice(vo.getSeckillPrice());
        orderInfo.setStatus(OrderInfo.STATUS_ARREARAGE);
        orderInfo.setCreateDate(new Date());
        orderInfo.setSeckillDate(new Date());
        orderInfo.setSeckillTime(time);
        orderInfo.setIntergral(vo.getIntergral());
        orderInfo.setSeckillId(seckillId);
        orderInfoMapper.insert(orderInfo);
        return orderInfo.getOrderNo();
    }

    @Override
    @Transactional
    public void timeoutCancel(OrderMQResult orderMQResult) {
        //判断订单状态是否为支付
        OrderInfo orderInfo = orderInfoMapper.find(orderMQResult.getOrderNo());
        if(orderInfo != null){
            //如果是未付款
            if(OrderInfo.STATUS_ARREARAGE.equals(orderInfo.getStatus())){
                //需要回补真实库存
                seckillProductMapper.incrStock(orderMQResult.getSeckillId());
                //回补预备库存
                seckillProductService.syncRedisStockCount(orderMQResult.getTime(), orderMQResult.getSeckillId());
                //修改本地标识
                rocketMQTemplate.sendOneWay(MQConstant.CANCEL_SECKILL_OVER_SIGE_TOPIC,orderMQResult.getSeckillId());
                //修改订单状态
                orderInfoMapper.updateCancelStatus(orderMQResult.getOrderNo(),OrderInfo.STATUS_TIMEOUT);
                log.info("超时取消的业务逻辑执行成功");
            }
        }
    }
}
